package nancal.mp.config.filter

import nbcp.base.extend.AsString
import nbcp.base.extend.ToMap
import nbcp.flux.getHeader
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cloud.gateway.filter.GatewayFilterChain
import org.springframework.cloud.gateway.filter.GlobalFilter
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory
import org.springframework.core.Ordered
import org.springframework.http.server.reactive.ServerHttpRequest
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import reactor.core.publisher.Mono

/**
 * 根据 schema Header 加工返回结果
 */
@Component
class SchemaFilter : GlobalFilter, Ordered {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)
    }

    @Autowired
    lateinit var modifyResponseBodyGatewayFilterFactory: ModifyResponseBodyGatewayFilterFactory;


    override fun filter(
        exchange: ServerWebExchange,
        chain: GatewayFilterChain
    ): Mono<Void> {
        var request = exchange.request as ServerHttpRequest;
        var schema = request.getHeader("schema");
        if (schema.isNullOrEmpty()) {
            return chain.filter(exchange);
        }

        //使用 Cookie 编码格式， Key=Value; Key=Value; Key
        var schemaMap = schema.split(";")
            .map { it.split("=") }
            .ToMap({ it.first().trim() }, { if (it.size == 1) true else it.last().trim() })

        if (schemaMap.size == 0) {
            return chain.filter(exchange);
        }

        /*
        Key和格式有：
        1. data: 默认值= data,list ， 表示哪个列返回的 list 数据, 可以有多个，多个用逗号分隔； 中间路径用 点 分隔。
        2. columns:a,b,c 只返回 data数组中的 a,b,c 三列。
        3. -columns:a,b,c 在返回列表的结果上，减去 a,b,c 三列。
        4. keys:a,b,c 仅保留 data 对象中的 a,b,c 三个属性
        5. -keys:a,b,c 在返回对象的结果上，减去 a,b,c 三个属性
         */

        var columns = schemaMap.get("columns").AsString()
            .split(",")
            .filter { it.isNotBlank() }
        var noColumns = schemaMap.get("-columns").AsString()
            .split(",")
            .filter { it.isNotBlank() }

        var keys = schemaMap.get("keys").AsString()
            .split(",")
            .filter { it.isNotBlank() }
        var noKeys = schemaMap.get("-keys").AsString()
            .split(",")
            .filter { it.isNotBlank() }

        if (columns.isEmpty() && noColumns.isEmpty() && keys.isEmpty() && noKeys.isEmpty()) {
            return chain.filter(exchange);
        }

        var paths = schemaMap.get("data").AsString("data,list").split(",")

        var config = ModifyResponseBodyGatewayFilterFactory.Config();
        config.rewriteFunction = ResponseRewriteFunction(paths, columns, noColumns,keys,noKeys);
        config.inClass = String::class.java
        config.outClass = String::class.java


        return modifyResponseBodyGatewayFilterFactory.apply(config)
            .filter(exchange, chain)
    }

    override fun getOrder(): Int {
        return Ordered.HIGHEST_PRECEDENCE
    }
}